﻿/**
<code>
  <author name="Zealic" email="zealic(at)gmail.com" type="Creator"/>
</code>
**/
using System;
using System.Runtime.InteropServices;


namespace Zealib
{
    public class ValueReference<T> : IDisposable
        where T : struct
    {
        private GCHandle m_Handle;

        ~ValueReference()
        {
            Dispose();
        }

        public ValueReference(object referenceObject)
        {
            if (referenceObject == null) throw new ArgumentNullException("referenceObject");
            if (!(referenceObject is T)) throw new ArgumentException("Invalid type.", "referenceObject");
            m_Handle = GCHandle.Alloc(referenceObject);
        }

        public T Value
        {
            get { return (T)m_Handle.Target; }
            set
            {
                IntPtr address = Marshal.ReadIntPtr(GCHandle.ToIntPtr(m_Handle));
                IntPtr dataAddress = new IntPtr((long)address + IntPtr.Size);
                Marshal.StructureToPtr(value, dataAddress, false);
            }
        }

        public void Dispose()
        {
            if (m_Handle.IsAllocated)
            {
                m_Handle.Free();
                GC.SuppressFinalize(this);
            }
        }
    }
}
